package blackeagle.ems.entities;

import blackeagle.ems.BlackEagleEMS;
import blackeagle.ems.Logger;
import blackeagle.ems.dal.DataClass;
import blackeagle.ems.dal.DataField;
import blackeagle.ems.dal.DataRecord;
import blackeagle.ems.dal.MethodType;
import blackeagle.ems.dal.Where;
import java.util.ArrayList;
import java.util.HashMap;
import se.oru.informatik.InformatikDB;
import se.oru.informatik.InformatikException;
import se.oru.informatik.StringHelper;

/**
 * A class representing a domain.
 */
@DataClass(dataName="\"DOMAIN\"")
public class Domain extends DataRecord<Domain> {
    private Integer id, departmentId, leadId;
    private String name;

    /**
     * The default 0-parameter constructor.
     */
    public Domain(){}
    
    /**
     * A static class containing read-only fields with column names.
     */
    public static class Columns{
        public static final String DepartmentId = "departmentid";
        public static final String Id = "id";
        public static final String LeadId = "leadid";
        public static final String Name = "name";
        
        private Columns(){}
    }
    
    /**
     * Fetches the department under which this domain is structured.
     * @return <code>null</code> if no department can be found; otherwise a department.
     */
    public Department getDepartment(){
        Department dept = null;
        
        try{
            dept = new Department().load(this.departmentId);
        }catch(Exception e){
            return null;
        }
        
        return ((dept!=null&&!dept.isNew())?dept:null);
    }
    
    /**
     * Sets the department of this domain.
     * @param dept The department under which this domain will be structured.
     */
    public void setDepartment(Department dept){
        Integer i = dept.getId();
        this.setDepartmentId(i);
    }
    
    /**
     * Gets the department id of this domain.
     * @return An integer containing the department id of this domain.
     */
    @DataField(fieldName="departmentid", methodType=MethodType.Getter)
    public Integer getDepartmentId() {
        return departmentId;
    }

    /**
     * Sets the department id of this domain.
     * @param departmentId A positive integer.
     */    
    @DataField(fieldName="departmentid", methodType=MethodType.Setter)
    public void setDepartmentId(Integer departmentId) {
        this.departmentId = departmentId;
        this._isDirty = true;
    }

    /**
     * Gets the id of this domain.
     * @return An integer containing the id of this domain.
     */
    @DataField(fieldName="id", methodType=MethodType.Getter, isPrimary=true, autoIncrement=true)
    public Integer getId(){
        return this.id;
    }
    
    /**
     * Sets this id of this domain
     * @param value A positive integer.
     */
    @DataField(fieldName="id", methodType=MethodType.Setter, isPrimary=true, autoIncrement=true)
    public void setId(Integer value){
        if(value>0){
            this.id=value;
            this._isDirty=true;
        }        
    }
    
    /**
     * Gets the Employee who is the leader of this domain.
     * @return An employee-record from the database if successful; otherwise <code>null</code>
     */
    public Employee getLead(){
        Employee e = new Employee().load(this.leadId);
        return (e.isNew()?null:e);
    }

    /**
     * Sets the leader of this domain.
     * @param lead An employee to set as leader of this domain.
     */
    public void setLead(Employee lead){
        Integer lId = lead.getId();
        this.setLeadId(lId);
    }
    
    /**
     * Gets the lead id of this domain.
     * @return An integer containing the lead id of this domain.
     */
    @DataField(fieldName="leadid", methodType=MethodType.Getter)
    public Integer getLeadId() {
        return leadId;
    }
    
    /**
     * Sets the lead id of this domain.
     * @param leadId A positive integer.
     */
    @DataField(fieldName="leadid", methodType=MethodType.Setter)
    public void setLeadId(Integer leadId) {
        this.leadId = leadId;
        this._isDirty = true;
    }

    /**
     * Gets the name of this domain.
     * @return A String containing the name of this domain.
     */
    @DataField(fieldName="name", methodType=MethodType.Getter)
    public String getName() {
        return name;
    }

    /**
     * Sets the name of this domain.
     * @param name A String containing the new name of this domain.
     */
    @DataField(fieldName="name", methodType=MethodType.Setter)
    public void setName(String name) {
        this.name = name;
        this._isDirty = true;
    }
    
    /**
     * Attempts to fetch all the Employees who are specialists in this domain.
     * @return An EmployeeCollection containing the employees who are specialists in this domain.
     */
    public EmployeeCollection getSpecialists(){
        EmployeeCollection ec = new EmployeeCollection();
        
        InformatikDB iDB = null;
        try{
            iDB=new InformatikDB(BlackEagleEMS.connectionString);
        }catch(InformatikException e){
            Logger.log(StringHelper.sprintf("Unable to connect to database (#)",e.getMessage()));
            
            return ec;
        }
        
        String query = StringHelper.sprintf("SELECT E.* FROM EMPLOYEE AS E INNER JOIN DOMAINSPECIALIST AS DS ON (DS.EMPLOYEEID=E.ID) WHERE DS.DOMAINID='#'",
                this.id);
        
        ArrayList<HashMap<String,String>> result = null;
        try{
            result = iDB.fetchRows(query);
        }catch(InformatikException e){
            Logger.log(StringHelper.sprintf("Unable to query the database (#)", e.getMessage()));
        }
        
        ec.loadData(result);
        
        return ec;
    }
    
    /**
     * Attempts to fetch all the Employees who are specialists of a given level in this domain.
     * @param level The level to match.
     * @return An EmployeeCollection containing the employees who are specialists of the given level in this domain.
     */
    public EmployeeCollection getSpecialists(Integer level){
        EmployeeCollection ec = new EmployeeCollection();
        if(level<1||level>3)return ec;
        
        InformatikDB iDB = null;
        try{
            iDB=new InformatikDB(BlackEagleEMS.connectionString);
        }catch(InformatikException e){
            Logger.log(StringHelper.sprintf("Unable to connect to database (#)",e.getMessage()));
            
            return ec;
        }
        
        String query = StringHelper.sprintf("SELECT E.* FROM EMPLOYEE AS E INNER JOIN DOMAINSPECIALIST AS DS ON (DS.EMPLOYEEID=E.ID) WHERE DS.DOMAINID='#' AND DS.LEVEL='#'",
                this.id, level);
        
        ArrayList<HashMap<String,String>> result = null;
        try{
            result = iDB.fetchRows(query);
        }catch(InformatikException e){
            Logger.log(StringHelper.sprintf("Unable to query the database (#)", e.getMessage()));
        }
        
        ec.loadData(result);
        
        return ec;
    }
    
    /**
     * Loads all the Subprojects linked to this domain.
     * @return A SubprojectCollection containing all the subprojects linked to this domain.
     */
    public SubprojectCollection getSubProjects(){
        return new SubprojectCollection()
                .where(new Where(Subproject.Columns.DomainId, this.id))
                .load();
    }
    
    @Override
    public String toString(){
        return this.name;
    }
}
